Loading packages

Loading the data:

model_4_21_95wRAW = NULL
model_2_7_21_new = NULL
model_2_7_21_new <- read_excel("~/Desktop/sage/model_2_7_21_newV4.xlsx")

model_4_21_95wRAW <- model_2_7_21_new
#library(tidyverse)
#model_4_21_95wRAW %>% select_if(negate(is.numeric))

dim(model_2_7_21_new)
[1] 2077   87
summPreds <- function(inpPred,inpTruth,inpMetrNms=c("err","acc","sens","spec")) {
  retVals <- numeric()
  for ( metrTmp in inpMetrNms ) {
    retVals[metrTmp] <- performance(prediction(inpPred,inpTruth),measure=metrTmp)@y.values[[1]][2]
  }
  retVals
}
    Train = NULL
    Test = NULL
    bTrain = sample(1:nrow(model_4_21_95wRAW),round(0.7*nrow(model_4_21_95wRAW)))
    Train <- model_4_21_95wRAW[bTrain,2:87]
    Test <- model_4_21_95wRAW[-bTrain,2:87]
    Test = as.data.frame(Test)
              Train$cat = as.numeric(as.factor(Train$cat))
          Test$cat = as.numeric(as.factor(Test$cat))
          
          
Y = factor(as.numeric(as.factor(Train$cat)))
tuneRF(Train[1:85],Y,ntreeTry = 300,plot=TRUE)
mtry = 9  OOB error = 0.96% 
Searching left ...
mtry = 5    OOB error = 1.44% 
-0.5 0.05 
Searching right ...
mtry = 18   OOB error = 0.41% 
0.5714286 0.05 
mtry = 36   OOB error = 0.55% 
-0.3333333 0.05 
       mtry    OOBError
5.OOB     5 0.014442916
9.OOB     9 0.009628611
18.OOB   18 0.004126547
36.OOB   36 0.005502063

Y = factor(as.numeric(as.factor(Train$cat)))
rfTmp <- randomForest(Y~.,data=Train[,1:85],mTry = 18,ntree = 1000)
rfTestPred <- predict(rfTmp,newdata=Test[,1:85])


mseTest <- mean((as.numeric(factor(Test$cat))-as.numeric(rfTestPred))) #Calculating the mean squared error
#tmpVals <- summPreds(as.numeric(factor(Test$cat)),as.numeric(rfTestPred))

VI_F=importance(rfTmp)
VI_F
                    MeanDecreaseGini
LNTcon1                    7.6357064
LNTcon2                    7.6823166
LNTcon3                    6.1456542
LNTfh1                     3.3675898
LNTfh2                     3.6810801
LNTfh3                     3.7280283
LNTreg1                   45.3698007
LNTreg2                   26.8094780
LNTreg3                   34.0956535
LNTfr1                    47.1328080
LNTfr2                    49.9809364
LNTfr3                    72.5765562
SpleenTcon1                3.6301799
SpleenTcon2                5.0774485
SpleenTcon3                2.7495229
SpleenTfh1                 1.7927661
SpleenTfh2                 1.7451146
SpleenTfh3                 3.2312894
SpleenTreg1               10.9382510
SpleenTreg2               16.5781411
SpleenTreg3               18.3344852
SpleenTfr1                12.5759806
SpleenTfr2                12.9644749
SpleenTfr3                 8.4423328
BloodTcon1                 8.8024146
BloodTcon2                 8.4828076
BloodTcon3                 7.2863457
BloodTfh1                  1.4808955
BloodTfh2                  1.5113150
BloodTfh3                  1.4598444
BloodTreg1                 5.1066351
BloodTreg2                 6.0971699
BloodTreg3                 7.1942529
BloodTfr1                  1.0420599
BloodTfr2                  0.9905301
BloodTfr3                  1.0568475
EZH2EXP_F_p_Treg_1         4.5791186
EZH2EXP_F_p_Treg_2         2.0443356
EZH2EXP_F_p_Treg_3         2.1459223
EZH2EXP_F_p_Tfr_1          7.8041261
EZH2EXP_F_p_Tfr_2         10.2892409
EZH2EXP_F_p_Tfr_3         10.9562897
BlimpEXP_F_p_Treg_1        4.5235946
BlimpEXP_F_p_Treg_2        3.5205116
BlimpEXP_F_p_Treg_3        2.1943278
BlimpEXP_F_p_Treg_4        3.3664066
BlimpEXP_F_p_Tfr_1         2.3628381
BlimpEXP_F_p_Tfr_2         4.9722807
BlimpEXP_F_p_Tfr_3         2.6237975
BlimpEXP_F_p_Tfr_4         2.1307726
FoxDownFoxP_Tfr_1          3.7171745
FoxDownFoxP_Tfr_2          2.0298604
FoxDownFoxP_Tfr_3          2.3420473
FoxDownFoxMTfr_1           1.4743007
FoxDownFoxMTfr_2           1.3139286
FoxDownFoxMTfr_3           1.1419481
FoxDown_Tfh_1              5.2228072
FoxDown_Tfh_2             15.1654368
FoxDown_Tfh_3              3.5967246
HDM_OVA_Tcon_1             9.7500222
HDM_OVA_Tcon_2             6.9236944
HDM_OVA_Tfh_1              1.3556755
HDM_OVA_Tfh_2              1.9274904
HDM_OVA_Tfr_1              1.4817007
HDM_OVA_Tfr_2              1.3912696
HDM_Tfh_1                  1.7202721
HDM_Tfh_2                  1.3921791
HDM_Tfr_1                  2.5219640
HDM_Tfr_2                  6.9118782
FoxF_CreN_Tcon_1          10.5643154
FoxF_CreN_Tcon_2           6.3363880
FoxF_CreN_Tcon_3           2.9943886
FoxF_CreN_Tcon_4           3.6819194
FoxF_CreN_Treg_1           2.2946092
FoxF_CreN_Treg_2           4.4240561
FoxF_CreN_Treg_3           2.0410392
FoxF_CreN_Treg_4           4.2720484
FoxF_CreN_ICOS_1          22.9569124
FoxF_CreN_ICOS_2          16.9067668
FoxF_CreN_ICOS_3          13.8311513
FoxF_CreN_ICOS_4          26.2319491
FoxF_CreN_Tfr_1            3.7286656
FoxF_CreN_Tfr_2            1.4987874
FoxF_CreN_Tfr_3           10.1542357
FoxF_CreN_Tfr_4            2.9102014
#pdf("Importance_plot.pdf")
varImpPlot(rfTmp,type=2)

#dev.off()

# LNTreg1                    43.447022
# LNTreg2                    27.107419
# LNTreg3                    32.783442
# LNTfr1                     53.615951
# LNTfr2                     52.316917
# LNTfr3                     67.765825
# FoxF_CreN_ICOS_4           29.519462
# pdf("Importance_plot.pdf")
# partialPlot(rfTmp,x.var="LNTfr3",pred.data = as.data.frame(Train),which.class = 2)
# partialPlot(rfTmp,x.var="LNTfr1",pred.data = as.data.frame(Train),which.class = 2)
# partialPlot(rfTmp,x.var="LNTfr2",pred.data = as.data.frame(Train),which.class = 2)
# partialPlot(rfTmp,x.var="LNTreg1",pred.data = as.data.frame(Train),which.class = 2)
# partialPlot(rfTmp,x.var="LNTreg3",pred.data = as.data.frame(Train),which.class = 2)
# partialPlot(rfTmp,x.var="LNTreg2",pred.data = as.data.frame(Train),which.class = 2)
# partialPlot(rfTmp,x.var="FoxF_CreN_ICOS_4",pred.data = as.data.frame(Train),which.class = 2)
# dev.off()
partialPlot(rfTmp,x.var="BloodTfr1",pred.data = as.data.frame(Train),which.class = 2)

partialPlot(rfTmp,x.var="BloodTfr2",pred.data = as.data.frame(Train),which.class = 2)

partialPlot(rfTmp,x.var="BloodTfr3",pred.data = as.data.frame(Train),which.class = 2)

# 
partialPlot(rfTmp,x.var="BloodTfr1",pred.data = as.data.frame(Train),which.class = 1)

partialPlot(rfTmp,x.var="BloodTfr2",pred.data = as.data.frame(Train),which.class = 1)

partialPlot(rfTmp,x.var="BloodTfr3",pred.data = as.data.frame(Train),which.class = 1)


#library(dplyr)
library(RColorBrewer)
imp <- as.data.frame(VI_F)
imp$varnames <- rownames(VI_F)
imp = imp %>% arrange(MeanDecreaseGini)
small = imp[65:85,]
#imp = order(imp)
dotchart(small$MeanDecreaseGini,labels = small$varnames,color = brewer.pal(n = 8, name = "Dark2"))



ggplot(data = small, aes(x = MeanDecreaseGini,y = reorder(varnames, MeanDecreaseGini))) +
geom_bar(stat="identity",fill = 'darkred')+
labs(y = "Condition") +
theme(legend.position = "top")




p = ggplot(small, aes(x = MeanDecreaseGini, y = reorder(varnames, MeanDecreaseGini))) +
  geom_point(aes(color = MeanDecreaseGini, size = MeanDecreaseGini), alpha = 0.5) 
  p
 ggsave(file="test.svg", plot=p, width=10, height=8)

library(readxl)
TfhTfr_Exon_AllGenes_combined <- read_excel("~/Desktop/sage/TfhTfr_Exon_AllGenes_combined.xlsx")

#Getting the class
#rfTestPred <- predict(rfTmp,newdata=TfhTfr_Exon_AllGenes_combined[,2:86])
rfTestPred <- predict(rfTmp,newdata=TfhTfr_Exon_AllGenes_combined[,2:86],type = "class")
#getting the probabilities
rfTestPred_prob <- predict(rfTmp,newdata=TfhTfr_Exon_AllGenes_combined[,2:86],type = "prob")

#Here I am trying to get some random names for the GSEA gene set.
random_names = character(2000)
random_names = sample(TfhTfr_Exon_AllGenes_combined$`Feature ID`,2000)
fileConn<-file("random_names.txt")
writeLines(random_names, fileConn)
close(fileConn)

2 is a Yes, 1 is a No

TfhTfr_Exon_AllGenes_combined = cbind(TfhTfr_Exon_AllGenes_combined,rfTestPred)
genes_vales = TfhTfr_Exon_AllGenes_combined[,c(1,87)]
genes_vales = cbind(genes_vales,rfTestPred_prob)

hist(as.numeric(genes_vales[,2]))

Here I generate an image of the final tree from the training/test data

#rfTestPred_prob
options(repos='http://cran.rstudio.org')
have.packages <- installed.packages()
cran.packages <- c('devtools','plotrix','randomForest','tree')
to.install <- setdiff(cran.packages, have.packages[,1])
if(length(to.install)>0) install.packages(to.install)

library(devtools)
Loading required package: usethis
if(!('reprtree' %in% installed.packages())){
  install_github('araastat/reprtree')
}
for(p in c(cran.packages, 'reprtree')) eval(substitute(library(pkg), list(pkg=p)))

Attaching package: ‘plotrix’

The following object is masked from ‘package:psych’:

    rescale
library(reprtree)

svg("TREE.svg",    width=20, height=20,pointsize = 5)
reprtree:::plot.getTree(rfTmp)
dev.off()
null device 
          1 

q-q plots of the p-values

qqnorm(rfTestPred_prob, pch = 1, frame = FALSE)
qqline(rfTestPred_prob, col = "steelblue", lwd = 2)

#genes_vales = cbind(genes_vales,rfTestPred_prob)
Yes_columns = NULL
Yes_columns = dplyr::filter( genes_vales, rfTestPred == 2 )
Yes_columns = data.frame(Yes_columns)
Yes_columns = Yes_columns[order(Yes_columns$X2,decreasing = TRUE),]
Yes_columns_sub = Yes_columns[1:2000,]
#View(Yes_columns_sub)


TfhTfr_Exon_AllGenes_combined_Yes = NULL
TfhTfr_Exon_AllGenes_combined_Yes = cbind(TfhTfr_Exon_AllGenes_combined,rfTestPred_prob)
TfhTfr_Exon_AllGenes_combined_Yes = dplyr::filter( TfhTfr_Exon_AllGenes_combined_Yes, rfTestPred == 2 )
TfhTfr_Exon_AllGenes_combined_Yes = data.frame(TfhTfr_Exon_AllGenes_combined_Yes)
TfhTfr_Exon_AllGenes_combined_Yes = TfhTfr_Exon_AllGenes_combined_Yes[order(TfhTfr_Exon_AllGenes_combined_Yes$X2,decreasing = TRUE),]
TfhTfr_Exon_AllGenes_combined_Yes_top_2000 = TfhTfr_Exon_AllGenes_combined_Yes[2:2000,]
library(pheatmap)

#small heatmap
genesList = c('Cxcr5','Icos','Pdcd1','Bcl6','Nrn1','Tnfrsf18','Gzmb','Sh2d1a','Prdm1','Cd44','Irf4','Ezh2','Il1r2','Cxcr7','Foxp3','Bcl6','Il2rg','Il2rb','Bcl6','Ctla4','Gata3','Id2','Il10','Maf')


colsToUse = 8:13
colsToUse = c(1,colsToUse)
McolsToUse = c(colsToUse,20:25) # Just Spleen
McolsToUse = c(McolsToUse,32:37) # Blood included
Tcon_McolsToUse = c(McolsToUse,2:4,14:16,26:28) # Tcon included

subsetYes = TfhTfr_Exon_AllGenes_combined_Yes[TfhTfr_Exon_AllGenes_combined_Yes$Feature.ID %in% genesList,colsToUse]

Copy_subsetYes = as.matrix(subsetYes[,2:7])
rownames(Copy_subsetYes) = subsetYes[,1]
p = pheatmap(Copy_subsetYes,cutree_rows = 2,cutree_cols = 2,scale = 'row',clustering_distance_cols = "canberra")
p

ggsave(file="subListYesGenes.svg", plot=p, width=10, height=8)

#with more cell types
More_cell_types = TfhTfr_Exon_AllGenes_combined_Yes[TfhTfr_Exon_AllGenes_combined_Yes$Feature.ID %in% genesList,McolsToUse]
#MCopy_subsetYes = as.matrix(More_cell_types[,2:13]) # with just spleen
MCopy_subsetYes = as.matrix(More_cell_types[,2:19]) #Blood included
colsReorder = c(1:3,7:9,13:15,4:6,10:12,16:18)
MCopy_subsetYes_reOrder = MCopy_subsetYes[,colsReorder] #re-ordered cols
rownames(MCopy_subsetYes) = More_cell_types[,1]
rownames(MCopy_subsetYes_reOrder) = More_cell_types[,1]
View(MCopy_subsetYes_reOrder)
p = pheatmap(MCopy_subsetYes,cutree_rows = 2,cutree_cols = 2,scale = 'row',clustering_distance_cols = "canberra")
p


RC_p = pheatmap(MCopy_subsetYes_reOrder,cutree_rows = 2,cutree_cols = 2,scale = 'row',clustering_distance_cols = "canberra")
RC_p

ggsave(file="Proper_order_subListYesGenes_cell_types.svg", plot=RC_p, width=10, height=8)

###############

#adding Tcon
T_con_More_cell_types = TfhTfr_Exon_AllGenes_combined_Yes[TfhTfr_Exon_AllGenes_combined_Yes$Feature.ID %in% genesList,Tcon_McolsToUse]
#MCopy_subsetYes = as.matrix(More_cell_types[,2:13]) # with just spleen
T_con_MCopy_subsetYes = as.matrix(T_con_More_cell_types[,2:28]) #Tcon included
colsReorder = c(1:6,19:21,7:12,22:24,13:18,25:27)
T_con_MCopy_subsetYes_reOrder = T_con_MCopy_subsetYes[,colsReorder] #re-ordered cols
rownames(T_con_MCopy_subsetYes) = More_cell_types[,1]
rownames(T_con_MCopy_subsetYes_reOrder) = More_cell_types[,1]
View(T_con_MCopy_subsetYes_reOrder)

T_con_RC_p = pheatmap(T_con_MCopy_subsetYes_reOrder,cutree_rows = 2,cutree_cols = 2,scale = 'row',clustering_distance_cols = "canberra")
T_con_RC_p

ggsave(file="Proper_order_subListYesGenes_cell_types_T_con_.svg", plot=T_con_RC_p, width=8, height=6)

##########
#large heatmap
holder = TfhTfr_Exon_AllGenes_combined_Yes_top_2000[1:50,8:13]
#View(holder)
holder = as.matrix(holder)

rownames(holder) = TfhTfr_Exon_AllGenes_combined_Yes_top_2000[1:50,1]


heatmap(holder)


p = pheatmap(holder,cutree_rows = 2,cutree_cols = 2,scale = 'row',clustering_distance_cols = "canberra")
p

ggsave(file="test.svg", plot=p, width=10, height=8)

#large Top 50
holder = NULL
holder = TfhTfr_Exon_AllGenes_combined_Yes_top_2000[1:50,McolsToUse]
#View(holder)
holder = as.matrix(holder[,2:19])

rownames(holder) = TfhTfr_Exon_AllGenes_combined_Yes_top_2000[1:50,1]


heatmap(holder)


p = pheatmap(holder,cutree_rows = 2,cutree_cols = 8,scale = 'row',clustering_distance_cols = "canberra")
p

ggsave(file="test.svg", plot=p, width=10, height=8)

Here I am working on the hclust linkage to see if there is one that better fits the columns

MCopy_subsetYes = as.matrix(More_cell_types[,2:19]) #Blood included
colsReorder = c(1:3,7:9,13:15,4:6,10:12,16:18)
MCopy_subsetYes_reOrder = MCopy_subsetYes[,colsReorder] #re-ordered cols
rownames(MCopy_subsetYes) = More_cell_types[,1]
rownames(MCopy_subsetYes_reOrder) = More_cell_types[,1]

p = pheatmap(MCopy_subsetYes,cutree_rows = 2,cutree_cols = 2,scale = 'row')
p


RC_p = pheatmap(MCopy_subsetYes_reOrder,cutree_rows = 2,cutree_cols = 2,scale = 'row',clustering_distance_cols = "canberra")
RC_p


#method 
 #"euclidean", "maximum", "manhattan", "canberra", "binary" or "minkowski". 

# Ward Hierarchical Clustering
d <- dist(MCopy_subsetYes_reOrder, method = "euclidean") # distance matrix
fit_WD <- hclust(d, method="ward.D") 
fit_WD2 <- hclust(d, method="ward.D2") 
fit_S <- hclust(d, method="single") 
fit_C <- hclust(d, method="complete") 
fit_A <- hclust(d, method="average") 
fit_MC <- hclust(d, method="mcquitty") 
fit_M <- hclust(d, method="median")
fit_CE <- hclust(d, method="centroid") 

library(gplots)
#rownames(TfhTfr_Exon_AllGenes_combined_Yes) = TfhTfr_Exon_AllGenes_combined_Yes[,2]
Ymatrix = unlist(TfhTfr_Exon_AllGenes_combined_Yes[1:5018,2:86])
Ymatrix = as.numeric(Ymatrix)
Ymatrix = matrix(v,nrow = 5018,ncol = 84)

heatmap(Ymatrix,symm = F,main = "Heatmap test",labRow = rownames(TfhTfr_Exon_AllGenes_combined_Yes))

Making the top calls for the other class.

TfhTfr_Exon_AllGenes_combined_No = NULL
TfhTfr_Exon_AllGenes_combined_No = cbind(TfhTfr_Exon_AllGenes_combined,rfTestPred_prob)
TfhTfr_Exon_AllGenes_combined_No = dplyr::filter( TfhTfr_Exon_AllGenes_combined_No, rfTestPred == 1 )
TfhTfr_Exon_AllGenes_combined_No = data.frame(TfhTfr_Exon_AllGenes_combined_No)
TfhTfr_Exon_AllGenes_combined_No = TfhTfr_Exon_AllGenes_combined_No[order(TfhTfr_Exon_AllGenes_combined_No$X1,decreasing = TRUE),]
TfhTfr_Exon_AllGenes_combined_No_top_1000 = TfhTfr_Exon_AllGenes_combined_No[1:1000,]

Looking at the top 50 from each class


TfhTfr_Exon_AllGenes_combined_Yes_top_50 = TfhTfr_Exon_AllGenes_combined_Yes[1:50,]
TfhTfr_Exon_AllGenes_combined_No_top_50 = TfhTfr_Exon_AllGenes_combined_No[1:50,]


groupCalls = rbind(TfhTfr_Exon_AllGenes_combined_Yes_top_50,TfhTfr_Exon_AllGenes_combined_No_top_50)

YNHeatmap_matrix = NULL
YNHeatmap_matrix = unlist(groupCalls[2:100,2:86])
YNHeatmap_matrix = as.numeric(v)
YNHeatmap_matrix = matrix(v,nrow = 98,ncol = 84)

heatmap(YNHeatmap_matrix,symm = F,main = "Heatmap test",labRow = rownames(groupCalls))
image(YNHeatmap_matrix)

write.csv(as.data.frame(Yes_columns_sub),file = "TFR_model_results_top_1000_genes.csv")
write.csv(as.data.frame(TfhTfr_Exon_AllGenes_combined_Yes),file = "TFR_model_results_Yes_genes.csv")
TfhTfr_Exon_AllGenes_combined_Yes_top_2000
write.csv(as.data.frame(TfhTfr_Exon_AllGenes_combined_Yes_top_2000),file = "TFR_model_results_Yes_genes_top_2000.csv")
write.csv(as.data.frame(TfhTfr_Exon_AllGenes_combined_No_top_1000),file = "TFR_model_results_No_genes_1000.csv")
write.csv(as.data.frame(TfhTfr_Exon_AllGenes_combined_No_top_1000),file = "TFR_model_results_No_genes_1000.csv")
write.csv(as.data.frame(groupCalls),file = "TFR_model_results_group.csv")

Not used

#BiocManager::install("M3C")
#library(M3C)

YmatrixNew = Ymatrix
#colnames(YmatrixNew) = colnames(TfhTfr_Exon_AllGenes_combined_Yes[,2:85])
umap(TfhTfr_Exon_AllGenes_combined_Yes[,2:86],colvec = as.factor(colnames(TfhTfr_Exon_AllGenes_combined_Yes[,2:86])),labels = as.factor(colnames(TfhTfr_Exon_AllGenes_combined_Yes[,2:86])))

#tfr.umap = umap(Ymatrix)
#tfr.umap
LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKTG9hZGluZyBwYWNrYWdlcwoKYGBge3IgbWVzc2FnZT1GQUxTRSwgaW5jbHVkZT1GQUxTRX0KbGlicmFyeShkcGx5cikKbGlicmFyeShuZXVyYWxuZXQpCmxpYnJhcnkocmVhZHhsKQpsaWJyYXJ5KGdyaWQpCmxpYnJhcnkoY29ycnBsb3QpCmxpYnJhcnkoY2FyZXQpCmxpYnJhcnkoZTEwNzEpCmxpYnJhcnkoUk9DUikKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KEdHYWxseSkKbGlicmFyeShQZXJmb3JtYW5jZUFuYWx5dGljcykKbGlicmFyeShmYWN0b2V4dHJhKQpsaWJyYXJ5KGNvcnJwbG90KQpsaWJyYXJ5KFJ0c25lKQpsaWJyYXJ5KEZhY3RvTWluZVIpCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShmYWN0b2V4dHJhKQpsaWJyYXJ5KHN1cnZtaW5lcikKbGlicmFyeShnZ2NvcnJwbG90KQpsaWJyYXJ5KHJlYWRyKQpsaWJyYXJ5KGNpcmNsaXplKQpsaWJyYXJ5KHJlYWR4bCkKbGlicmFyeShzdHJpbmdyKQpsaWJyYXJ5KHJlc2hhcGUpCmxpYnJhcnkocHN5Y2gpCmxpYnJhcnkoQ29tcGxleEhlYXRtYXApCmxpYnJhcnkoZ2dwdWJyKQpsaWJyYXJ5KHJlYWRyKQpsaWJyYXJ5KGdyaWRFeHRyYSkKbGlicmFyeShjb3dwbG90KQpsaWJyYXJ5KE1BU1MpCmxpYnJhcnkoZml0ZGlzdHJwbHVzKQojQmlvY01hbmFnZXI6Omluc3RhbGwoInByZXByb2Nlc3NDb3JlIikKbGlicmFyeShwcmVwcm9jZXNzQ29yZSkKbGlicmFyeShNQVNTKQpsaWJyYXJ5KGNsYXNzKQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkocmVzaGFwZTIpCmxpYnJhcnkoUk9DUikKbGlicmFyeShlMTA3MSkKbGlicmFyeShHR2FsbHkpCmxpYnJhcnkoa2xhUikKbGlicmFyeShyYW5kb21Gb3Jlc3QpCgpgYGAKCkxvYWRpbmcgdGhlIGRhdGE6CgoKYGBge3J9Cm1vZGVsXzRfMjFfOTV3UkFXID0gTlVMTAptb2RlbF8yXzdfMjFfbmV3ID0gTlVMTAptb2RlbF8yXzdfMjFfbmV3IDwtIHJlYWRfZXhjZWwoIn4vRGVza3RvcC9zYWdlL21vZGVsXzJfN18yMV9uZXdWNC54bHN4IikKCm1vZGVsXzRfMjFfOTV3UkFXIDwtIG1vZGVsXzJfN18yMV9uZXcKI2xpYnJhcnkodGlkeXZlcnNlKQojbW9kZWxfNF8yMV85NXdSQVcgJT4lIHNlbGVjdF9pZihuZWdhdGUoaXMubnVtZXJpYykpCgpkaW0obW9kZWxfMl83XzIxX25ldykKYGBgCgpgYGB7cn0Kc3VtbVByZWRzIDwtIGZ1bmN0aW9uKGlucFByZWQsaW5wVHJ1dGgsaW5wTWV0ck5tcz1jKCJlcnIiLCJhY2MiLCJzZW5zIiwic3BlYyIpKSB7CiAgcmV0VmFscyA8LSBudW1lcmljKCkKICBmb3IgKCBtZXRyVG1wIGluIGlucE1ldHJObXMgKSB7CiAgICByZXRWYWxzW21ldHJUbXBdIDwtIHBlcmZvcm1hbmNlKHByZWRpY3Rpb24oaW5wUHJlZCxpbnBUcnV0aCksbWVhc3VyZT1tZXRyVG1wKUB5LnZhbHVlc1tbMV1dWzJdCiAgfQogIHJldFZhbHMKfQpgYGAKCgpgYGB7cn0KICAgIFRyYWluID0gTlVMTAogICAgVGVzdCA9IE5VTEwKICAgIGJUcmFpbiA9IHNhbXBsZSgxOm5yb3cobW9kZWxfNF8yMV85NXdSQVcpLHJvdW5kKDAuNypucm93KG1vZGVsXzRfMjFfOTV3UkFXKSkpCiAgICBUcmFpbiA8LSBtb2RlbF80XzIxXzk1d1JBV1tiVHJhaW4sMjo4N10KICAgIFRlc3QgPC0gbW9kZWxfNF8yMV85NXdSQVdbLWJUcmFpbiwyOjg3XQogICAgVGVzdCA9IGFzLmRhdGEuZnJhbWUoVGVzdCkKICAgICAgICAgICAgICBUcmFpbiRjYXQgPSBhcy5udW1lcmljKGFzLmZhY3RvcihUcmFpbiRjYXQpKQogICAgICAgICAgVGVzdCRjYXQgPSBhcy5udW1lcmljKGFzLmZhY3RvcihUZXN0JGNhdCkpCiAgICAgICAgICAKICAgICAgICAgIApgYGAKCmBgYHtyfQpZID0gZmFjdG9yKGFzLm51bWVyaWMoYXMuZmFjdG9yKFRyYWluJGNhdCkpKQp0dW5lUkYoVHJhaW5bMTo4NV0sWSxudHJlZVRyeSA9IDMwMCxwbG90PVRSVUUpCmBgYAoKCgpgYGB7ciBlY2hvPVRSVUV9ClkgPSBmYWN0b3IoYXMubnVtZXJpYyhhcy5mYWN0b3IoVHJhaW4kY2F0KSkpCnJmVG1wIDwtIHJhbmRvbUZvcmVzdChZfi4sZGF0YT1UcmFpblssMTo4NV0sbVRyeSA9IDE4LG50cmVlID0gMTAwMCkKcmZUZXN0UHJlZCA8LSBwcmVkaWN0KHJmVG1wLG5ld2RhdGE9VGVzdFssMTo4NV0pCgoKbXNlVGVzdCA8LSBtZWFuKChhcy5udW1lcmljKGZhY3RvcihUZXN0JGNhdCkpLWFzLm51bWVyaWMocmZUZXN0UHJlZCkpKSAjQ2FsY3VsYXRpbmcgdGhlIG1lYW4gc3F1YXJlZCBlcnJvcgojdG1wVmFscyA8LSBzdW1tUHJlZHMoYXMubnVtZXJpYyhmYWN0b3IoVGVzdCRjYXQpKSxhcy5udW1lcmljKHJmVGVzdFByZWQpKQoKVklfRj1pbXBvcnRhbmNlKHJmVG1wKQpWSV9GCiNwZGYoIkltcG9ydGFuY2VfcGxvdC5wZGYiKQp2YXJJbXBQbG90KHJmVG1wLHR5cGU9MikKI2Rldi5vZmYoKQoKIyBMTlRyZWcxICAgICAgICAgICAgICAgICAgICA0My40NDcwMjIKIyBMTlRyZWcyICAgICAgICAgICAgICAgICAgICAyNy4xMDc0MTkKIyBMTlRyZWczICAgICAgICAgICAgICAgICAgICAzMi43ODM0NDIKIyBMTlRmcjEgICAgICAgICAgICAgICAgICAgICA1My42MTU5NTEKIyBMTlRmcjIgICAgICAgICAgICAgICAgICAgICA1Mi4zMTY5MTcKIyBMTlRmcjMgICAgICAgICAgICAgICAgICAgICA2Ny43NjU4MjUKIyBGb3hGX0NyZU5fSUNPU180ICAgICAgICAgICAyOS41MTk0NjIKIyBwZGYoIkltcG9ydGFuY2VfcGxvdC5wZGYiKQojIHBhcnRpYWxQbG90KHJmVG1wLHgudmFyPSJMTlRmcjMiLHByZWQuZGF0YSA9IGFzLmRhdGEuZnJhbWUoVHJhaW4pLHdoaWNoLmNsYXNzID0gMikKIyBwYXJ0aWFsUGxvdChyZlRtcCx4LnZhcj0iTE5UZnIxIixwcmVkLmRhdGEgPSBhcy5kYXRhLmZyYW1lKFRyYWluKSx3aGljaC5jbGFzcyA9IDIpCiMgcGFydGlhbFBsb3QocmZUbXAseC52YXI9IkxOVGZyMiIscHJlZC5kYXRhID0gYXMuZGF0YS5mcmFtZShUcmFpbiksd2hpY2guY2xhc3MgPSAyKQojIHBhcnRpYWxQbG90KHJmVG1wLHgudmFyPSJMTlRyZWcxIixwcmVkLmRhdGEgPSBhcy5kYXRhLmZyYW1lKFRyYWluKSx3aGljaC5jbGFzcyA9IDIpCiMgcGFydGlhbFBsb3QocmZUbXAseC52YXI9IkxOVHJlZzMiLHByZWQuZGF0YSA9IGFzLmRhdGEuZnJhbWUoVHJhaW4pLHdoaWNoLmNsYXNzID0gMikKIyBwYXJ0aWFsUGxvdChyZlRtcCx4LnZhcj0iTE5UcmVnMiIscHJlZC5kYXRhID0gYXMuZGF0YS5mcmFtZShUcmFpbiksd2hpY2guY2xhc3MgPSAyKQojIHBhcnRpYWxQbG90KHJmVG1wLHgudmFyPSJGb3hGX0NyZU5fSUNPU180IixwcmVkLmRhdGEgPSBhcy5kYXRhLmZyYW1lKFRyYWluKSx3aGljaC5jbGFzcyA9IDIpCiMgZGV2Lm9mZigpCnBhcnRpYWxQbG90KHJmVG1wLHgudmFyPSJCbG9vZFRmcjEiLHByZWQuZGF0YSA9IGFzLmRhdGEuZnJhbWUoVHJhaW4pLHdoaWNoLmNsYXNzID0gMikKcGFydGlhbFBsb3QocmZUbXAseC52YXI9IkJsb29kVGZyMiIscHJlZC5kYXRhID0gYXMuZGF0YS5mcmFtZShUcmFpbiksd2hpY2guY2xhc3MgPSAyKQpwYXJ0aWFsUGxvdChyZlRtcCx4LnZhcj0iQmxvb2RUZnIzIixwcmVkLmRhdGEgPSBhcy5kYXRhLmZyYW1lKFRyYWluKSx3aGljaC5jbGFzcyA9IDIpCiMgCnBhcnRpYWxQbG90KHJmVG1wLHgudmFyPSJCbG9vZFRmcjEiLHByZWQuZGF0YSA9IGFzLmRhdGEuZnJhbWUoVHJhaW4pLHdoaWNoLmNsYXNzID0gMSkKcGFydGlhbFBsb3QocmZUbXAseC52YXI9IkJsb29kVGZyMiIscHJlZC5kYXRhID0gYXMuZGF0YS5mcmFtZShUcmFpbiksd2hpY2guY2xhc3MgPSAxKQpwYXJ0aWFsUGxvdChyZlRtcCx4LnZhcj0iQmxvb2RUZnIzIixwcmVkLmRhdGEgPSBhcy5kYXRhLmZyYW1lKFRyYWluKSx3aGljaC5jbGFzcyA9IDEpCgojbGlicmFyeShkcGx5cikKbGlicmFyeShSQ29sb3JCcmV3ZXIpCmltcCA8LSBhcy5kYXRhLmZyYW1lKFZJX0YpCmltcCR2YXJuYW1lcyA8LSByb3duYW1lcyhWSV9GKQppbXAgPSBpbXAgJT4lIGFycmFuZ2UoTWVhbkRlY3JlYXNlR2luaSkKc21hbGwgPSBpbXBbNjU6ODUsXQojaW1wID0gb3JkZXIoaW1wKQpkb3RjaGFydChzbWFsbCRNZWFuRGVjcmVhc2VHaW5pLGxhYmVscyA9IHNtYWxsJHZhcm5hbWVzLGNvbG9yID0gYnJld2VyLnBhbChuID0gOCwgbmFtZSA9ICJEYXJrMiIpKQoKCmdncGxvdChkYXRhID0gc21hbGwsIGFlcyh4ID0gTWVhbkRlY3JlYXNlR2luaSx5ID0gcmVvcmRlcih2YXJuYW1lcywgTWVhbkRlY3JlYXNlR2luaSkpKSArCmdlb21fYmFyKHN0YXQ9ImlkZW50aXR5IixmaWxsID0gJ2RhcmtyZWQnKSsKbGFicyh5ID0gIkNvbmRpdGlvbiIpICsKdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIpCgoKCnAgPSBnZ3Bsb3Qoc21hbGwsIGFlcyh4ID0gTWVhbkRlY3JlYXNlR2luaSwgeSA9IHJlb3JkZXIodmFybmFtZXMsIE1lYW5EZWNyZWFzZUdpbmkpKSkgKwogIGdlb21fcG9pbnQoYWVzKGNvbG9yID0gTWVhbkRlY3JlYXNlR2luaSwgc2l6ZSA9IE1lYW5EZWNyZWFzZUdpbmkpLCBhbHBoYSA9IDAuNSkgCiAgcAogZ2dzYXZlKGZpbGU9InRlc3Quc3ZnIiwgcGxvdD1wLCB3aWR0aD0xMCwgaGVpZ2h0PTgpCgpgYGAKCgoKYGBge3J9CmxpYnJhcnkocmVhZHhsKQpUZmhUZnJfRXhvbl9BbGxHZW5lc19jb21iaW5lZCA8LSByZWFkX2V4Y2VsKCJ+L0Rlc2t0b3Avc2FnZS9UZmhUZnJfRXhvbl9BbGxHZW5lc19jb21iaW5lZC54bHN4IikKCiNHZXR0aW5nIHRoZSBjbGFzcwojcmZUZXN0UHJlZCA8LSBwcmVkaWN0KHJmVG1wLG5ld2RhdGE9VGZoVGZyX0V4b25fQWxsR2VuZXNfY29tYmluZWRbLDI6ODZdKQpyZlRlc3RQcmVkIDwtIHByZWRpY3QocmZUbXAsbmV3ZGF0YT1UZmhUZnJfRXhvbl9BbGxHZW5lc19jb21iaW5lZFssMjo4Nl0sdHlwZSA9ICJjbGFzcyIpCiNnZXR0aW5nIHRoZSBwcm9iYWJpbGl0aWVzCnJmVGVzdFByZWRfcHJvYiA8LSBwcmVkaWN0KHJmVG1wLG5ld2RhdGE9VGZoVGZyX0V4b25fQWxsR2VuZXNfY29tYmluZWRbLDI6ODZdLHR5cGUgPSAicHJvYiIpCgojSGVyZSBJIGFtIHRyeWluZyB0byBnZXQgc29tZSByYW5kb20gbmFtZXMgZm9yIHRoZSBHU0VBIGdlbmUgc2V0LgpyYW5kb21fbmFtZXMgPSBjaGFyYWN0ZXIoMjAwMCkKcmFuZG9tX25hbWVzID0gc2FtcGxlKFRmaFRmcl9FeG9uX0FsbEdlbmVzX2NvbWJpbmVkJGBGZWF0dXJlIElEYCwyMDAwKQpmaWxlQ29ubjwtZmlsZSgicmFuZG9tX25hbWVzLnR4dCIpCndyaXRlTGluZXMocmFuZG9tX25hbWVzLCBmaWxlQ29ubikKY2xvc2UoZmlsZUNvbm4pCmBgYAoKMiBpcyBhIFllcywgMSBpcyBhIE5vCmBgYHtyfQpUZmhUZnJfRXhvbl9BbGxHZW5lc19jb21iaW5lZCA9IGNiaW5kKFRmaFRmcl9FeG9uX0FsbEdlbmVzX2NvbWJpbmVkLHJmVGVzdFByZWQpCmdlbmVzX3ZhbGVzID0gVGZoVGZyX0V4b25fQWxsR2VuZXNfY29tYmluZWRbLGMoMSw4NyldCmdlbmVzX3ZhbGVzID0gY2JpbmQoZ2VuZXNfdmFsZXMscmZUZXN0UHJlZF9wcm9iKQoKaGlzdChhcy5udW1lcmljKGdlbmVzX3ZhbGVzWywyXSkpCmBgYAoKSGVyZSBJIGdlbmVyYXRlIGFuIGltYWdlIG9mIHRoZSBmaW5hbCB0cmVlIGZyb20gdGhlIHRyYWluaW5nL3Rlc3QgZGF0YQpgYGB7cn0KI3JmVGVzdFByZWRfcHJvYgpvcHRpb25zKHJlcG9zPSdodHRwOi8vY3Jhbi5yc3R1ZGlvLm9yZycpCmhhdmUucGFja2FnZXMgPC0gaW5zdGFsbGVkLnBhY2thZ2VzKCkKY3Jhbi5wYWNrYWdlcyA8LSBjKCdkZXZ0b29scycsJ3Bsb3RyaXgnLCdyYW5kb21Gb3Jlc3QnLCd0cmVlJykKdG8uaW5zdGFsbCA8LSBzZXRkaWZmKGNyYW4ucGFja2FnZXMsIGhhdmUucGFja2FnZXNbLDFdKQppZihsZW5ndGgodG8uaW5zdGFsbCk+MCkgaW5zdGFsbC5wYWNrYWdlcyh0by5pbnN0YWxsKQoKbGlicmFyeShkZXZ0b29scykKaWYoISgncmVwcnRyZWUnICVpbiUgaW5zdGFsbGVkLnBhY2thZ2VzKCkpKXsKICBpbnN0YWxsX2dpdGh1YignYXJhYXN0YXQvcmVwcnRyZWUnKQp9CmZvcihwIGluIGMoY3Jhbi5wYWNrYWdlcywgJ3JlcHJ0cmVlJykpIGV2YWwoc3Vic3RpdHV0ZShsaWJyYXJ5KHBrZyksIGxpc3QocGtnPXApKSkKbGlicmFyeShyZXBydHJlZSkKCnN2ZygiVFJFRS5zdmciLCAgICB3aWR0aD0yMCwgaGVpZ2h0PTIwLHBvaW50c2l6ZSA9IDUpCnJlcHJ0cmVlOjo6cGxvdC5nZXRUcmVlKHJmVG1wKQpkZXYub2ZmKCkKCmBgYAoKcS1xIHBsb3RzIG9mIHRoZSBwLXZhbHVlcwpgYGB7cn0KcXFub3JtKHJmVGVzdFByZWRfcHJvYiwgcGNoID0gMSwgZnJhbWUgPSBGQUxTRSkKcXFsaW5lKHJmVGVzdFByZWRfcHJvYiwgY29sID0gInN0ZWVsYmx1ZSIsIGx3ZCA9IDIpCmBgYAoKCmBgYHtyfQojZ2VuZXNfdmFsZXMgPSBjYmluZChnZW5lc192YWxlcyxyZlRlc3RQcmVkX3Byb2IpClllc19jb2x1bW5zID0gTlVMTApZZXNfY29sdW1ucyA9IGRwbHlyOjpmaWx0ZXIoIGdlbmVzX3ZhbGVzLCByZlRlc3RQcmVkID09IDIgKQpZZXNfY29sdW1ucyA9IGRhdGEuZnJhbWUoWWVzX2NvbHVtbnMpClllc19jb2x1bW5zID0gWWVzX2NvbHVtbnNbb3JkZXIoWWVzX2NvbHVtbnMkWDIsZGVjcmVhc2luZyA9IFRSVUUpLF0KWWVzX2NvbHVtbnNfc3ViID0gWWVzX2NvbHVtbnNbMToyMDAwLF0KI1ZpZXcoWWVzX2NvbHVtbnNfc3ViKQoKClRmaFRmcl9FeG9uX0FsbEdlbmVzX2NvbWJpbmVkX1llcyA9IE5VTEwKVGZoVGZyX0V4b25fQWxsR2VuZXNfY29tYmluZWRfWWVzID0gY2JpbmQoVGZoVGZyX0V4b25fQWxsR2VuZXNfY29tYmluZWQscmZUZXN0UHJlZF9wcm9iKQpUZmhUZnJfRXhvbl9BbGxHZW5lc19jb21iaW5lZF9ZZXMgPSBkcGx5cjo6ZmlsdGVyKCBUZmhUZnJfRXhvbl9BbGxHZW5lc19jb21iaW5lZF9ZZXMsIHJmVGVzdFByZWQgPT0gMiApClRmaFRmcl9FeG9uX0FsbEdlbmVzX2NvbWJpbmVkX1llcyA9IGRhdGEuZnJhbWUoVGZoVGZyX0V4b25fQWxsR2VuZXNfY29tYmluZWRfWWVzKQpUZmhUZnJfRXhvbl9BbGxHZW5lc19jb21iaW5lZF9ZZXMgPSBUZmhUZnJfRXhvbl9BbGxHZW5lc19jb21iaW5lZF9ZZXNbb3JkZXIoVGZoVGZyX0V4b25fQWxsR2VuZXNfY29tYmluZWRfWWVzJFgyLGRlY3JlYXNpbmcgPSBUUlVFKSxdClRmaFRmcl9FeG9uX0FsbEdlbmVzX2NvbWJpbmVkX1llc190b3BfMjAwMCA9IFRmaFRmcl9FeG9uX0FsbEdlbmVzX2NvbWJpbmVkX1llc1syOjIwMDAsXQoKYGBgCgpgYGB7cn0KbGlicmFyeShwaGVhdG1hcCkKCiNzbWFsbCBoZWF0bWFwCmdlbmVzTGlzdCA9IGMoJ0N4Y3I1JywnSWNvcycsJ1BkY2QxJywnQmNsNicsJ05ybjEnLCdUbmZyc2YxOCcsJ0d6bWInLCdTaDJkMWEnLCdQcmRtMScsJ0NkNDQnLCdJcmY0JywnRXpoMicsJ0lsMXIyJywnQ3hjcjcnLCdGb3hwMycsJ0JjbDYnLCdJbDJyZycsJ0lsMnJiJywnQmNsNicsJ0N0bGE0JywnR2F0YTMnLCdJZDInLCdJbDEwJywnTWFmJykKCgpjb2xzVG9Vc2UgPSA4OjEzCmNvbHNUb1VzZSA9IGMoMSxjb2xzVG9Vc2UpCk1jb2xzVG9Vc2UgPSBjKGNvbHNUb1VzZSwyMDoyNSkgIyBKdXN0IFNwbGVlbgpNY29sc1RvVXNlID0gYyhNY29sc1RvVXNlLDMyOjM3KSAjIEJsb29kIGluY2x1ZGVkClRjb25fTWNvbHNUb1VzZSA9IGMoTWNvbHNUb1VzZSwyOjQsMTQ6MTYsMjY6MjgpICMgVGNvbiBpbmNsdWRlZAoKc3Vic2V0WWVzID0gVGZoVGZyX0V4b25fQWxsR2VuZXNfY29tYmluZWRfWWVzW1RmaFRmcl9FeG9uX0FsbEdlbmVzX2NvbWJpbmVkX1llcyRGZWF0dXJlLklEICVpbiUgZ2VuZXNMaXN0LGNvbHNUb1VzZV0KCkNvcHlfc3Vic2V0WWVzID0gYXMubWF0cml4KHN1YnNldFllc1ssMjo3XSkKcm93bmFtZXMoQ29weV9zdWJzZXRZZXMpID0gc3Vic2V0WWVzWywxXQpwID0gcGhlYXRtYXAoQ29weV9zdWJzZXRZZXMsY3V0cmVlX3Jvd3MgPSAyLGN1dHJlZV9jb2xzID0gMixzY2FsZSA9ICdyb3cnLGNsdXN0ZXJpbmdfZGlzdGFuY2VfY29scyA9ICJjYW5iZXJyYSIpCnAKZ2dzYXZlKGZpbGU9InN1Ykxpc3RZZXNHZW5lcy5zdmciLCBwbG90PXAsIHdpZHRoPTEwLCBoZWlnaHQ9OCkKCiN3aXRoIG1vcmUgY2VsbCB0eXBlcwpNb3JlX2NlbGxfdHlwZXMgPSBUZmhUZnJfRXhvbl9BbGxHZW5lc19jb21iaW5lZF9ZZXNbVGZoVGZyX0V4b25fQWxsR2VuZXNfY29tYmluZWRfWWVzJEZlYXR1cmUuSUQgJWluJSBnZW5lc0xpc3QsTWNvbHNUb1VzZV0KI01Db3B5X3N1YnNldFllcyA9IGFzLm1hdHJpeChNb3JlX2NlbGxfdHlwZXNbLDI6MTNdKSAjIHdpdGgganVzdCBzcGxlZW4KTUNvcHlfc3Vic2V0WWVzID0gYXMubWF0cml4KE1vcmVfY2VsbF90eXBlc1ssMjoxOV0pICNCbG9vZCBpbmNsdWRlZApjb2xzUmVvcmRlciA9IGMoMTozLDc6OSwxMzoxNSw0OjYsMTA6MTIsMTY6MTgpCk1Db3B5X3N1YnNldFllc19yZU9yZGVyID0gTUNvcHlfc3Vic2V0WWVzWyxjb2xzUmVvcmRlcl0gI3JlLW9yZGVyZWQgY29scwpyb3duYW1lcyhNQ29weV9zdWJzZXRZZXMpID0gTW9yZV9jZWxsX3R5cGVzWywxXQpyb3duYW1lcyhNQ29weV9zdWJzZXRZZXNfcmVPcmRlcikgPSBNb3JlX2NlbGxfdHlwZXNbLDFdClZpZXcoTUNvcHlfc3Vic2V0WWVzX3JlT3JkZXIpCnAgPSBwaGVhdG1hcChNQ29weV9zdWJzZXRZZXMsY3V0cmVlX3Jvd3MgPSAyLGN1dHJlZV9jb2xzID0gMixzY2FsZSA9ICdyb3cnLGNsdXN0ZXJpbmdfZGlzdGFuY2VfY29scyA9ICJjYW5iZXJyYSIpCnAKClJDX3AgPSBwaGVhdG1hcChNQ29weV9zdWJzZXRZZXNfcmVPcmRlcixjdXRyZWVfcm93cyA9IDIsY3V0cmVlX2NvbHMgPSAyLHNjYWxlID0gJ3JvdycsY2x1c3RlcmluZ19kaXN0YW5jZV9jb2xzID0gImNhbmJlcnJhIikKUkNfcApnZ3NhdmUoZmlsZT0iUHJvcGVyX29yZGVyX3N1Ykxpc3RZZXNHZW5lc19jZWxsX3R5cGVzLnN2ZyIsIHBsb3Q9UkNfcCwgd2lkdGg9MTAsIGhlaWdodD04KQoKIyMjIyMjIyMjIyMjIyMjCgojYWRkaW5nIFRjb24KVF9jb25fTW9yZV9jZWxsX3R5cGVzID0gVGZoVGZyX0V4b25fQWxsR2VuZXNfY29tYmluZWRfWWVzW1RmaFRmcl9FeG9uX0FsbEdlbmVzX2NvbWJpbmVkX1llcyRGZWF0dXJlLklEICVpbiUgZ2VuZXNMaXN0LFRjb25fTWNvbHNUb1VzZV0KI01Db3B5X3N1YnNldFllcyA9IGFzLm1hdHJpeChNb3JlX2NlbGxfdHlwZXNbLDI6MTNdKSAjIHdpdGgganVzdCBzcGxlZW4KVF9jb25fTUNvcHlfc3Vic2V0WWVzID0gYXMubWF0cml4KFRfY29uX01vcmVfY2VsbF90eXBlc1ssMjoyOF0pICNUY29uIGluY2x1ZGVkCmNvbHNSZW9yZGVyID0gYygxOjYsMTk6MjEsNzoxMiwyMjoyNCwxMzoxOCwyNToyNykKVF9jb25fTUNvcHlfc3Vic2V0WWVzX3JlT3JkZXIgPSBUX2Nvbl9NQ29weV9zdWJzZXRZZXNbLGNvbHNSZW9yZGVyXSAjcmUtb3JkZXJlZCBjb2xzCnJvd25hbWVzKFRfY29uX01Db3B5X3N1YnNldFllcykgPSBNb3JlX2NlbGxfdHlwZXNbLDFdCnJvd25hbWVzKFRfY29uX01Db3B5X3N1YnNldFllc19yZU9yZGVyKSA9IE1vcmVfY2VsbF90eXBlc1ssMV0KVmlldyhUX2Nvbl9NQ29weV9zdWJzZXRZZXNfcmVPcmRlcikKClRfY29uX1JDX3AgPSBwaGVhdG1hcChUX2Nvbl9NQ29weV9zdWJzZXRZZXNfcmVPcmRlcixjdXRyZWVfcm93cyA9IDIsY3V0cmVlX2NvbHMgPSAyLHNjYWxlID0gJ3JvdycsY2x1c3RlcmluZ19kaXN0YW5jZV9jb2xzID0gImNhbmJlcnJhIikKVF9jb25fUkNfcApnZ3NhdmUoZmlsZT0iUHJvcGVyX29yZGVyX3N1Ykxpc3RZZXNHZW5lc19jZWxsX3R5cGVzX1RfY29uXy5zdmciLCBwbG90PVRfY29uX1JDX3AsIHdpZHRoPTgsIGhlaWdodD02KQoKIyMjIyMjIyMjIwojbGFyZ2UgaGVhdG1hcApob2xkZXIgPSBUZmhUZnJfRXhvbl9BbGxHZW5lc19jb21iaW5lZF9ZZXNfdG9wXzIwMDBbMTo1MCw4OjEzXQojVmlldyhob2xkZXIpCmhvbGRlciA9IGFzLm1hdHJpeChob2xkZXIpCgpyb3duYW1lcyhob2xkZXIpID0gVGZoVGZyX0V4b25fQWxsR2VuZXNfY29tYmluZWRfWWVzX3RvcF8yMDAwWzE6NTAsMV0KCgpoZWF0bWFwKGhvbGRlcikKCnAgPSBwaGVhdG1hcChob2xkZXIsY3V0cmVlX3Jvd3MgPSAyLGN1dHJlZV9jb2xzID0gMixzY2FsZSA9ICdyb3cnLGNsdXN0ZXJpbmdfZGlzdGFuY2VfY29scyA9ICJjYW5iZXJyYSIpCnAKZ2dzYXZlKGZpbGU9InRlc3Quc3ZnIiwgcGxvdD1wLCB3aWR0aD0xMCwgaGVpZ2h0PTgpCgojbGFyZ2UgVG9wIDUwCmhvbGRlciA9IE5VTEwKaG9sZGVyID0gVGZoVGZyX0V4b25fQWxsR2VuZXNfY29tYmluZWRfWWVzX3RvcF8yMDAwWzE6NTAsTWNvbHNUb1VzZV0KI1ZpZXcoaG9sZGVyKQpob2xkZXIgPSBhcy5tYXRyaXgoaG9sZGVyWywyOjE5XSkKCnJvd25hbWVzKGhvbGRlcikgPSBUZmhUZnJfRXhvbl9BbGxHZW5lc19jb21iaW5lZF9ZZXNfdG9wXzIwMDBbMTo1MCwxXQoKCmhlYXRtYXAoaG9sZGVyKQoKcCA9IHBoZWF0bWFwKGhvbGRlcixjdXRyZWVfcm93cyA9IDIsY3V0cmVlX2NvbHMgPSA4LHNjYWxlID0gJ3JvdycsY2x1c3RlcmluZ19kaXN0YW5jZV9jb2xzID0gImNhbmJlcnJhIikKcApnZ3NhdmUoZmlsZT0idGVzdC5zdmciLCBwbG90PXAsIHdpZHRoPTEwLCBoZWlnaHQ9OCkKCmBgYAoKSGVyZSBJIGFtIHdvcmtpbmcgb24gdGhlIGhjbHVzdCBsaW5rYWdlIHRvIHNlZSBpZiB0aGVyZSBpcyBvbmUgdGhhdCBiZXR0ZXIgZml0cyB0aGUgY29sdW1ucwpgYGB7cn0KTUNvcHlfc3Vic2V0WWVzID0gYXMubWF0cml4KE1vcmVfY2VsbF90eXBlc1ssMjoxOV0pICNCbG9vZCBpbmNsdWRlZApjb2xzUmVvcmRlciA9IGMoMTozLDc6OSwxMzoxNSw0OjYsMTA6MTIsMTY6MTgpCk1Db3B5X3N1YnNldFllc19yZU9yZGVyID0gTUNvcHlfc3Vic2V0WWVzWyxjb2xzUmVvcmRlcl0gI3JlLW9yZGVyZWQgY29scwpyb3duYW1lcyhNQ29weV9zdWJzZXRZZXMpID0gTW9yZV9jZWxsX3R5cGVzWywxXQpyb3duYW1lcyhNQ29weV9zdWJzZXRZZXNfcmVPcmRlcikgPSBNb3JlX2NlbGxfdHlwZXNbLDFdCgpwID0gcGhlYXRtYXAoTUNvcHlfc3Vic2V0WWVzLGN1dHJlZV9yb3dzID0gMixjdXRyZWVfY29scyA9IDIsc2NhbGUgPSAncm93JykKcAoKUkNfcCA9IHBoZWF0bWFwKE1Db3B5X3N1YnNldFllc19yZU9yZGVyLGN1dHJlZV9yb3dzID0gMixjdXRyZWVfY29scyA9IDIsc2NhbGUgPSAncm93JyxjbHVzdGVyaW5nX2Rpc3RhbmNlX2NvbHMgPSAiY2FuYmVycmEiKQpSQ19wCgojbWV0aG9kCQogIyJldWNsaWRlYW4iLCAibWF4aW11bSIsICJtYW5oYXR0YW4iLCAiY2FuYmVycmEiLCAiYmluYXJ5IiBvciAibWlua293c2tpIi4gCgojIFdhcmQgSGllcmFyY2hpY2FsIENsdXN0ZXJpbmcKZCA8LSBkaXN0KE1Db3B5X3N1YnNldFllc19yZU9yZGVyLCBtZXRob2QgPSAiZXVjbGlkZWFuIikgIyBkaXN0YW5jZSBtYXRyaXgKZml0X1dEIDwtIGhjbHVzdChkLCBtZXRob2Q9IndhcmQuRCIpIApmaXRfV0QyIDwtIGhjbHVzdChkLCBtZXRob2Q9IndhcmQuRDIiKSAKZml0X1MgPC0gaGNsdXN0KGQsIG1ldGhvZD0ic2luZ2xlIikgCmZpdF9DIDwtIGhjbHVzdChkLCBtZXRob2Q9ImNvbXBsZXRlIikgCmZpdF9BIDwtIGhjbHVzdChkLCBtZXRob2Q9ImF2ZXJhZ2UiKSAKZml0X01DIDwtIGhjbHVzdChkLCBtZXRob2Q9Im1jcXVpdHR5IikgCmZpdF9NIDwtIGhjbHVzdChkLCBtZXRob2Q9Im1lZGlhbiIpCmZpdF9DRSA8LSBoY2x1c3QoZCwgbWV0aG9kPSJjZW50cm9pZCIpIAoKCgpgYGAKCgoKCmBgYHtyfQoKbGlicmFyeShncGxvdHMpCiNyb3duYW1lcyhUZmhUZnJfRXhvbl9BbGxHZW5lc19jb21iaW5lZF9ZZXMpID0gVGZoVGZyX0V4b25fQWxsR2VuZXNfY29tYmluZWRfWWVzWywyXQpZbWF0cml4ID0gdW5saXN0KFRmaFRmcl9FeG9uX0FsbEdlbmVzX2NvbWJpbmVkX1llc1sxOjUwMTgsMjo4Nl0pClltYXRyaXggPSBhcy5udW1lcmljKFltYXRyaXgpClltYXRyaXggPSBtYXRyaXgodixucm93ID0gNTAxOCxuY29sID0gODQpCgpoZWF0bWFwKFltYXRyaXgsc3ltbSA9IEYsbWFpbiA9ICJIZWF0bWFwIHRlc3QiLGxhYlJvdyA9IHJvd25hbWVzKFRmaFRmcl9FeG9uX0FsbEdlbmVzX2NvbWJpbmVkX1llcykpCmBgYAoKTWFraW5nIHRoZSB0b3AgY2FsbHMgZm9yIHRoZSBvdGhlciBjbGFzcy4KCmBgYHtyfQpUZmhUZnJfRXhvbl9BbGxHZW5lc19jb21iaW5lZF9ObyA9IE5VTEwKVGZoVGZyX0V4b25fQWxsR2VuZXNfY29tYmluZWRfTm8gPSBjYmluZChUZmhUZnJfRXhvbl9BbGxHZW5lc19jb21iaW5lZCxyZlRlc3RQcmVkX3Byb2IpClRmaFRmcl9FeG9uX0FsbEdlbmVzX2NvbWJpbmVkX05vID0gZHBseXI6OmZpbHRlciggVGZoVGZyX0V4b25fQWxsR2VuZXNfY29tYmluZWRfTm8sIHJmVGVzdFByZWQgPT0gMSApClRmaFRmcl9FeG9uX0FsbEdlbmVzX2NvbWJpbmVkX05vID0gZGF0YS5mcmFtZShUZmhUZnJfRXhvbl9BbGxHZW5lc19jb21iaW5lZF9ObykKVGZoVGZyX0V4b25fQWxsR2VuZXNfY29tYmluZWRfTm8gPSBUZmhUZnJfRXhvbl9BbGxHZW5lc19jb21iaW5lZF9Ob1tvcmRlcihUZmhUZnJfRXhvbl9BbGxHZW5lc19jb21iaW5lZF9ObyRYMSxkZWNyZWFzaW5nID0gVFJVRSksXQpUZmhUZnJfRXhvbl9BbGxHZW5lc19jb21iaW5lZF9Ob190b3BfMTAwMCA9IFRmaFRmcl9FeG9uX0FsbEdlbmVzX2NvbWJpbmVkX05vWzE6MTAwMCxdCgpgYGAKCkxvb2tpbmcgYXQgdGhlIHRvcCA1MCBmcm9tIGVhY2ggY2xhc3MKYGBge3J9CgpUZmhUZnJfRXhvbl9BbGxHZW5lc19jb21iaW5lZF9ZZXNfdG9wXzUwID0gVGZoVGZyX0V4b25fQWxsR2VuZXNfY29tYmluZWRfWWVzWzE6NTAsXQpUZmhUZnJfRXhvbl9BbGxHZW5lc19jb21iaW5lZF9Ob190b3BfNTAgPSBUZmhUZnJfRXhvbl9BbGxHZW5lc19jb21iaW5lZF9Ob1sxOjUwLF0KCgpncm91cENhbGxzID0gcmJpbmQoVGZoVGZyX0V4b25fQWxsR2VuZXNfY29tYmluZWRfWWVzX3RvcF81MCxUZmhUZnJfRXhvbl9BbGxHZW5lc19jb21iaW5lZF9Ob190b3BfNTApCgpZTkhlYXRtYXBfbWF0cml4ID0gTlVMTApZTkhlYXRtYXBfbWF0cml4ID0gdW5saXN0KGdyb3VwQ2FsbHNbMjoxMDAsMjo4Nl0pCllOSGVhdG1hcF9tYXRyaXggPSBhcy5udW1lcmljKHYpCllOSGVhdG1hcF9tYXRyaXggPSBtYXRyaXgodixucm93ID0gOTgsbmNvbCA9IDg0KQoKaGVhdG1hcChZTkhlYXRtYXBfbWF0cml4LHN5bW0gPSBGLG1haW4gPSAiSGVhdG1hcCB0ZXN0IixsYWJSb3cgPSByb3duYW1lcyhncm91cENhbGxzKSkKaW1hZ2UoWU5IZWF0bWFwX21hdHJpeCkKCmBgYAoKCmBgYHtyfQoKd3JpdGUuY3N2KGFzLmRhdGEuZnJhbWUoWWVzX2NvbHVtbnNfc3ViKSxmaWxlID0gIlRGUl9tb2RlbF9yZXN1bHRzX3RvcF8xMDAwX2dlbmVzLmNzdiIpCndyaXRlLmNzdihhcy5kYXRhLmZyYW1lKFRmaFRmcl9FeG9uX0FsbEdlbmVzX2NvbWJpbmVkX1llcyksZmlsZSA9ICJURlJfbW9kZWxfcmVzdWx0c19ZZXNfZ2VuZXMuY3N2IikKVGZoVGZyX0V4b25fQWxsR2VuZXNfY29tYmluZWRfWWVzX3RvcF8yMDAwCndyaXRlLmNzdihhcy5kYXRhLmZyYW1lKFRmaFRmcl9FeG9uX0FsbEdlbmVzX2NvbWJpbmVkX1llc190b3BfMjAwMCksZmlsZSA9ICJURlJfbW9kZWxfcmVzdWx0c19ZZXNfZ2VuZXNfdG9wXzIwMDAuY3N2IikKd3JpdGUuY3N2KGFzLmRhdGEuZnJhbWUoVGZoVGZyX0V4b25fQWxsR2VuZXNfY29tYmluZWRfTm9fdG9wXzEwMDApLGZpbGUgPSAiVEZSX21vZGVsX3Jlc3VsdHNfTm9fZ2VuZXNfMTAwMC5jc3YiKQp3cml0ZS5jc3YoYXMuZGF0YS5mcmFtZShUZmhUZnJfRXhvbl9BbGxHZW5lc19jb21iaW5lZF9Ob190b3BfMTAwMCksZmlsZSA9ICJURlJfbW9kZWxfcmVzdWx0c19Ob19nZW5lc18xMDAwLmNzdiIpCndyaXRlLmNzdihhcy5kYXRhLmZyYW1lKGdyb3VwQ2FsbHMpLGZpbGUgPSAiVEZSX21vZGVsX3Jlc3VsdHNfZ3JvdXAuY3N2IikKYGBgCgpOb3QgdXNlZApgYGB7cn0KI0Jpb2NNYW5hZ2VyOjppbnN0YWxsKCJNM0MiKQojbGlicmFyeShNM0MpCgpZbWF0cml4TmV3ID0gWW1hdHJpeAojY29sbmFtZXMoWW1hdHJpeE5ldykgPSBjb2xuYW1lcyhUZmhUZnJfRXhvbl9BbGxHZW5lc19jb21iaW5lZF9ZZXNbLDI6ODVdKQp1bWFwKFRmaFRmcl9FeG9uX0FsbEdlbmVzX2NvbWJpbmVkX1llc1ssMjo4Nl0sY29sdmVjID0gYXMuZmFjdG9yKGNvbG5hbWVzKFRmaFRmcl9FeG9uX0FsbEdlbmVzX2NvbWJpbmVkX1llc1ssMjo4Nl0pKSxsYWJlbHMgPSBhcy5mYWN0b3IoY29sbmFtZXMoVGZoVGZyX0V4b25fQWxsR2VuZXNfY29tYmluZWRfWWVzWywyOjg2XSkpKQoKI3Rmci51bWFwID0gdW1hcChZbWF0cml4KQojdGZyLnVtYXAKYGBgCgo=